package com.geek.project.geekverificationcodestarter.service.kaptcha.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.geek.project.geekredisstarter.service.RedisService;
import com.geek.project.geekverificationcodestarter.exception.VerifyCodeException;
import com.geek.project.geekverificationcodestarter.props.SmsProperties;
import com.geek.project.geekverificationcodestarter.props.VerifyCodeProperties;
import com.geek.project.geekverificationcodestarter.service.kaptcha.VerifyCodeService;
import com.geek.project.geekverificationcodestarter.service.sms.SmsService;
import com.geek.project.geekverificationcodestarter.utils.DateUtil;
import com.geek.project.geekverificationcodestarter.utils.FileToBase64;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import lombok.extern.slf4j.Slf4j;

import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;

/**
 * 验证码实现类
 *
 * @author: geek
 */
@Slf4j
public class VerifyCodeServiceImpl implements VerifyCodeService {

    public static final String VERIFY_ID = "VerifyId";


    private DefaultKaptcha producer;

    private RedisService redisService;
    private SmsService smsService;
    private SmsProperties smsProperties;
    private VerifyCodeProperties verifyCodeProperties;

    public VerifyCodeServiceImpl(DefaultKaptcha producer, RedisService redisService, SmsService smsService, SmsProperties smsProperties, VerifyCodeProperties verifyCodeProperties) {
        this.producer = producer;
        this.redisService = redisService;
        this.smsService = smsService;
        this.smsProperties = smsProperties;
        this.verifyCodeProperties = verifyCodeProperties;
    }

    /**
     * 生成验证码
     *
     * @author geek
     * @param key
     * @return
     */
    @Override
    public Map<String, String> generalVerifyCode(String key) {
        return this.generalVerifyCode(key, true);
    }

    /**
     * 生成验证码
     *
     * @author geek
     * @param key
     * @param flag
     * @return
     */
    public Map<String, String> generalVerifyCode(String key, boolean flag) {
        Map<String, String> result = new HashMap<>();
        try {
            String verifyCode = producer.createText();
            BufferedImage image = producer.createImage(verifyCode);
            String base64Image = FileToBase64.getImage(image);
            redisService.set(key, verifyCode.toLowerCase(), verifyCodeProperties.getExpireTime());
            if (flag){
                result.put(VERIFY_ID, key);
            }
            result.put("IMAGE", base64Image);
            result.put("code", verifyCode);
        } catch (Exception e){
            throw new VerifyCodeException("验证码创建失败", e);
        }
        return result;
    }

    /**
     * 发送登录短信验证码
     *
     * @author geek
     * @param phone 电话号码
     * @param phoneCode 验证码
     */
    @Override
    public String sendLogin(String phone, String phoneCode) {
        Map<String, Object> map = new HashMap<>();
        map.put("code", phoneCode);
        return smsService.sendSms(phone, "login", JSONUtil.toJsonStr(map));
    }
    /**
     * 发送手机验证码
     *
     * @author geek
     * @param phone
     * @return
     */
    @Override
    public Map<String, String> generalPhoneVerifyCode(String phone) {
        Map<String, String> result = new HashMap<>();
        String verifyCode = producer.createText();

        String msg = this.sendLogin(phone, verifyCode);

        if (!smsProperties.isEnabled()){
            result.put("msg", msg);
        }

        if (!this.checkCount(phone)){
            throw new VerifyCodeException("今日验证码获取次数已达上限!");
        }
        redisService.set(String.format("%s:%s:code", verifyCodeProperties.getPhonePrefix(), phone), verifyCode.toLowerCase(), verifyCodeProperties.getExpireTime());
        redisService.increment(String.format("%s:%s:limit", verifyCodeProperties.getPhonePrefix(), phone),1, DateUtil.getTimeLeftSeconds());
        return result;
    }

    /**
     * 验证短信发送次数
     *
     * @author geek
     * @param phone
     * @return
     */
    public boolean checkCount(String phone){
        Object code = redisService.get(String.format("%s:%s:limit", verifyCodeProperties.getPhonePrefix(), phone));
        Integer limit = verifyCodeProperties.getMaxLimit();
        if (ObjectUtil.isNotNull(code)){
            Long value = Long.valueOf(code.toString());
            if (value > limit){
                return false;
            }
        }
        return true;
    }

    /**
     * 验证手机验证码
     *
     * @author geek
     * @param phone
     * @param code
     * @return
     */
    @Override
    public boolean verifyPhoneCode(String phone,String code) {
        return this.verifyCode(String.format("%s:%s:code", verifyCodeProperties.getPhonePrefix(), phone), code);
    }

    /**
     * 验证验证码
     *
     * @author geek
     * @param key
     * @param code
     * @return
     */
    @Override
    public boolean verifyCode(String key, String code) {
        Object object = redisService.get(key);
        if (object == null) {
            return false;
        }
        if (object.toString().toLowerCase().equals(code.toLowerCase())) {
            //验证成功 删除验证码
            redisService.del(key);
            return true;
        }
        return false;
    }

}
